home *** CD-ROM | disk | FTP | other *** search
- PROGRAM EASY_3D;
-
- {
- Very simple source code to illustrate 3D-rotations and delay-vektorz
- Do what ya want with it.. its totally free..
-
- It's just a 'one-hour' type project, enough time to write it down in
- the editor, fix the typo errors and comment it... so ya should not
- expect it to make somme coffee or anything else than giving a concrete
- example of VERY basic 3D calculus.
-
- Oh yes! It has been tested only in 640*480 VGA, so in other modes there
- might be some problems..
-
-
- Code By
-
- (\ ) /) |_) /) ) (\/)
- ( \) / ) | / ) \__ ( )
- }
-
-
-
- Uses Crt, Graph;
-
- Type
-
- Vect3D = Array[1..3] of LongInt;
- Mat33 = Array[1..3,1..3] of LongInt;
-
- Point2D = Record
- X,Y : LongInt;
- End;
- Point3D = Record
- X,Y,Z : LongInt;
- End;
-
- Poly3D_3 = Array[1..3] of Point3D;
- Poly3D_4 = Array[1..4] of Point3D;
- Poly2D_3 = Array[1..3] of Point2D;
- Poly2D_4 = Array[1..4] of Point2D;
-
- Var
- Face, FaceRot : Poly3D_4;{ Original coords / Rotated coords }
-
- FaceProj, OldProj,
- OldProj2, OldProj3,
- OldProj4 : Poly2D_4;{ Projected coords / "Delay" coords }
-
- RotXYZ : Mat33; { Rotation matrix around X, Y & Z }
-
- angle_x, angle_y,
- angle_z : Integer; { Angles of rotations around X, Y & Z }
-
- dist2screen : Integer; { Distance from Eye/Viewpoint to screen }
-
- xi, yi, zi : byte; { Increments for angles / Rotation speed }
- oldxi, oldyi, oldzi : byte;
-
- Fin, Frozen : Boolean;
-
- Const
- Maxli = 10;
- usage : Array[1..Maxli] of string =
- ('╔═════════════════════╗',
- '║ ║',
- '╟─────╥───────────────╨─────────╖',
- '║ 8,2 ║ X axis rotation speed ║',
- '║ 4,6 ║ Y axis rotation speed ║',
- '║ 9,1 ║ Z axis rotation speed ║',
- '║ +,- ║ Zoom in / Zoom out ║',
- '║ F ║ Freeze / Unfreeze ║',
- '║ ESC ║ Get Out ! ║',
- '╚═════╩═════════════════════════╝');
-
-
- (*------------------------------------------------------------------------*)
- { Initialize the video mode }
-
- PROCEDURE InitVid;
- var gd,gm : integer;
- Begin
- Gd:=Detect;
- InitGraph(Gd,Gm,'');
- If GraphResult<>GrOk then halt;
-
- SetLineStyle( SolidLn, 1, ThickWidth);
- End;
- (*------------------------------------------------------------------------*)
- { Initialize coordinates of the plane (=Face) }
-
- PROCEDURE InitFace;
- Var i : byte;
- Begin
- Face[1].X:=10;
- Face[1].Y:=10;
- Face[1].Z:=0;
- Face[2].X:=10;
- Face[2].Y:=-10;
- Face[2].Z:=0;
- Face[3].X:=-10;
- Face[3].Y:=-10;
- Face[3].Z:=0;
- Face[4].X:=-10;
- Face[4].Y:=10;
- Face[4].Z:=0;
-
- For i:=1 to 4 do
- Begin
- OldProj[i].X:=Face[i].X;
- OldProj[i].Y:=Face[i].Y;
- OldProj2[i].X:=Face[i].X;
- OldProj2[i].Y:=Face[i].Y;
- OldProj3[i].X:=Face[i].X;
- OldProj3[i].Y:=Face[i].Y;
- OldProj4[i].X:=Face[i].X;
- OldProj4[i].Y:=Face[i].Y;
- End;
- End;
- (*------------------------------------------------------------------------*)
- { Multiply all 4 points of the plane by 3x3 Matrix }
-
- PROCEDURE MAT_MUL_FACE( SF : Poly3D_4; VAR DF : Poly3D_4; MAT : Mat33);
- var i : byte;
-
- Begin
- DF[1].X:=SF[1].X * MAT[1][1] + SF[1].Y * MAT[1][2] + SF[1].Z * MAT[1][3];
- DF[1].Y:=SF[1].X * MAT[2][1] + SF[1].Y * MAT[2][2] + SF[1].Z * MAT[2][3];
- DF[1].Z:=SF[1].X * MAT[3][1] + SF[1].Y * MAT[3][2] + SF[1].Z * MAT[3][3];
-
- DF[2].X:=SF[2].X * MAT[1][1] + SF[2].Y * MAT[1][2] + SF[2].Z * MAT[1][3];
- DF[2].Y:=SF[2].X * MAT[2][1] + SF[2].Y * MAT[2][2] + SF[2].Z * MAT[2][3];
- DF[2].Z:=SF[2].X * MAT[3][1] + SF[2].Y * MAT[3][2] + SF[2].Z * MAT[3][3];
-
- DF[3].X:=SF[3].X * MAT[1][1] + SF[3].Y * MAT[1][2] + SF[3].Z * MAT[1][3];
- DF[3].Y:=SF[3].X * MAT[2][1] + SF[3].Y * MAT[2][2] + SF[3].Z * MAT[2][3];
- DF[3].Z:=SF[3].X * MAT[3][1] + SF[3].Y * MAT[3][2] + SF[3].Z * MAT[3][3];
-
- DF[4].X:=SF[4].X * MAT[1][1] + SF[4].Y * MAT[1][2] + SF[4].Z * MAT[1][3];
- DF[4].Y:=SF[4].X * MAT[2][1] + SF[4].Y * MAT[2][2] + SF[4].Z * MAT[2][3];
- DF[4].Z:=SF[4].X * MAT[3][1] + SF[4].Y * MAT[3][2] + SF[4].Z * MAT[3][3];
- End;
- (*------------------------------------------------------------------------*)
- { 3D to 2D plane coordinates projection }
-
- PROCEDURE PROJ_FACE( SF : Poly3D_4; VAR DF : Poly2D_4; tot : Integer);
- Var factor : Byte;
- dosc : LongInt;
-
- Begin
-
- dosc:=dist2screen;
- factor:=50;
-
- SF[1].Z:=(dosc+5)*16384;
- DF[1].X:=Round(factor * SF[1].X / SF[1].Z);
- DF[1].Y:=Round(factor * SF[1].Y / SF[1].Z);
-
- SF[2].Z:=(5+dosc)*16384;
- DF[2].X:=Round(factor * SF[2].X / SF[2].Z);
- DF[2].Y:=Round(factor * SF[2].Y / SF[2].Z);
-
- SF[3].Z:=(5+dosc)*16384;
- DF[3].X:=Round(factor * SF[3].X / SF[3].Z);
- DF[3].Y:=Round(factor * SF[3].Y / SF[3].Z);
-
- SF[4].Z:=(5+dosc)*16384;
- DF[4].X:=Round(factor * SF[4].X / SF[4].Z);
- DF[4].Y:=Round(factor * SF[4].Y / SF[4].Z);
-
- End;
- (*------------------------------------------------------------------------*)
- { Draws a 4 points polygon with 4 points (DrawPoly needs 5) }
-
- PROCEDURE DrawP( F : Poly2D_4);
- Var oldx, oldy : Word;
-
- Begin
- Line( F[1].X, F[1].Y, F[2].X, F[2].Y);
- Line( F[2].X, F[2].Y, F[3].X, F[3].Y);
- Line( F[3].X, F[3].Y, F[4].X, F[4].Y);
- Line( F[4].X, F[4].Y, F[1].X, F[1].Y);
- End;
- (*------------------------------------------------------------------------*)
- { Displays a 4 points polygon on screen with "delay" display of old }
- { positions ... }
-
- PROCEDURE DRAW_FACE( SF : Poly2D_4);
- var i : byte;
- Begin
-
- {
- Oh yeah! This is not beautiful code (far from it !!) but the effect is
- cute... A linked list would prevent all those unoptimized data-moves
- but again this code is here just to illustrate 3D rotations...
- }
-
- SetColor(0);
- DrawP( OldProj);
- SetColor( 1);
- DrawP( OldProj2);
- SetColor( 9);
- DrawP( OldProj3);
- SetColor( 11);
- DrawP( OldProj4);
-
- For i:=1 to 4 do
- Begin
- SF[i].X:=SF[i].X+320;
- SF[i].Y:=SF[i].Y+240;
- End;
-
- SetColor(15);
- DrawP( SF);
-
- For i:=1 to 4 do
- Begin
- OldProj[i].X:=OldProj2[i].X;
- OldProj[i].Y:=OldProj2[i].Y;
- OldProj2[i].X:=OldProj3[i].X;
- OldProj2[i].Y:=OldProj3[i].Y;
- OldProj3[i].X:=OldProj4[i].X; { Yerk ! }
- OldProj3[i].Y:=OldProj4[i].Y;
- OldProj4[i].X:=SF[i].X;
- OldProj4[i].Y:=SF[i].Y;
- End;
- End;
- (*------------------------------------------------------------------------*)
- { Computes the rotation matrix for the given angles, rotates, projects }
- { and display the 4 points plane }
-
-
- PROCEDURE Rotate( ax, ay, az : Integer; dist_s : Integer);
- Var x, y, z : Real;
- Begin
- x:=ax * Pi / 180;
- y:=ay * Pi / 180;
- z:=az * Pi / 180;
-
- {
- The "magical" MATRIX, rotates a vektor around X-Y-Z a the same
- time.
-
- ┌ ┐
- │ cZ*cY -cY*sZ sY │
- │ cX*sZ-sY*cZ*sX cZ*cX+sX*sZ*sY cY*sX │
- │-sX*sZ-sY*cZ*cX -cZ*sX+sZ*sY*cX cX*cY │
- └ ┘
-
- X -> Rotation angle around X-axis
- Y -> Rotation angle around Y-axis
- Z -> Rotation angle around Z-axis
-
- cZ -> COS(Z) sZ -> SIN(Z)
- cX -> COS(X) ....
-
- We use here a factor (i.e: 16384) to keep a certain precision
- during calculations as we use 32bit-integers. This code is designed to
- be translated to assembly, where SIN and COS are precalculated and
- where IEEE floating point is to be banned.
-
- Of course during the calculus of projections we divide by 16384.
-
- Why 16384 ?
- If ya know some assembly, this division can be done using arithmetic
- bit-shifts that are very fast compared to signed-division.
- }
-
- If NOT ((xi=0) AND (yi=0) AND (zi=0)) then
- Begin
- RotXYZ[1][1]:=Round(cos(z)*cos(y)*16384);
- RotXYZ[1][2]:=Round(-sin(z)*cos(y)*16384);
- RotXYZ[1][3]:=Round(sin(y)*16384);
- RotXYZ[2][1]:=Round((cos(x)*sin(z)-sin(y)*cos(z)*sin(x))*16384);
- RotXYZ[2][2]:=Round((cos(z)*cos(x)+sin(x)*sin(z)*sin(y))*16384);
- RotXYZ[2][3]:=Round(cos(y)*sin(x)*16384);
- RotXYZ[3][1]:=Round((-sin(x)*sin(z)-sin(y)*cos(z)*cos(x))*16384);
- RotXYZ[3][2]:=Round((-cos(z)*sin(x)+sin(z)*sin(y)*cos(x))*16384);
- RotXYZ[3][3]:=Round(cos(x)*cos(y)*16384);
-
- MAT_MUL_FACE( Face, FaceRot, RotXYZ);
- PROJ_FACE( FaceRot, FaceProj, dist_s);
- DRAW_FACE( FaceProj);
- End;
- End;
- (*------------------------------------------------------------------------*)
- { Displays usable commands during animation }
-
- PROCEDURE DispDoc;
- Var i : byte;
- Begin
- SetColor(14);
- OutTextXY( 19,18, 'Available commands');
-
- SetColor(7);
-
- For i:=1 to Maxli do
- OutTextXY( 2, 2+i*8, usage[i]);
-
- End;
- (*------------------------------------------------------------------------*)
-
-
- (*------------------------------------------------------------------------*)
- (* MAIN PROGRAM *)
- (*------------------------------------------------------------------------*)
- Var thekey : char;
-
- BEGIN
- Fin:=False;
- Frozen:=False;
- dist2screen:=5;
- InitVid;
- DispDoc;
- InitFace;
- xi:=3;
- yi:=4;
- zi:=5;
- Repeat
- If KeyPressed then
- Begin
- thekey:=ReadKey;
- case thekey of
- '6' : if NOT( Frozen) then yi:=yi + 1;
- '4' : if NOT( Frozen) AND (yi > 0) then
- yi:=yi - 1;
-
- '8' : if NOT( Frozen) then xi:=xi + 1;
- '2' : if NOT( Frozen) AND (xi > 0) then
- xi:=xi - 1;
-
- '9' : if NOT( Frozen) then zi:=zi + 1;
- '1' : if NOT( Frozen) AND (zi > 0) then
- zi:=zi - 1;
-
- '+' : if NOT( Frozen) AND (dist2screen > 0) then
- dist2screen:=dist2screen - 1;
-
- '-' : if NOT( Frozen) AND (dist2screen < 40) then
- dist2screen:=dist2screen + 1;
- 'F',
- 'f' : Begin
- If NOT( Frozen) then
- Begin
- oldxi:=xi;
- oldyi:=yi;
- oldzi:=zi;
- xi:=0;
- yi:=0;
- zi:=0;
- Frozen:=true;
- End
- Else
- Begin
- xi:=oldxi;
- yi:=oldyi;
- zi:=oldzi;
- Frozen:=false;
- End;
- End;
-
- #27 : Fin:=true
- end
- End;
- angle_x:=(angle_x + xi) mod 360;
- angle_y:=(angle_y + yi) mod 360;
- angle_z:=(angle_z + zi) mod 360;
- delay( 15*3);
- Rotate( angle_x, angle_y, angle_z, dist2screen);
- Until Fin;
- RestoreCrtMode
- END.
-